package com.zzyl.utils;

import java.time.LocalDate;
import java.time.format.DateTimeFormatter;
import java.time.format.DateTimeParseException;
import java.util.regex.Pattern;

/**
 * 身份证验证工具类
 */
public class IdCardValidator {

    // 身份证号码正则表达式（18位）
    private static final String ID_CARD_18_REGEX = "^[1-9]\\d{5}(18|19|20)\\d{2}((0[1-9])|(1[0-2]))(([0-2][1-9])|10|20|30|31)\\d{3}[0-9Xx]$";
    
    // 身份证号码正则表达式（15位）
    private static final String ID_CARD_15_REGEX = "^[1-9]\\d{5}\\d{2}((0[1-9])|(1[0-2]))(([0-2][1-9])|10|20|30|31)\\d{2}[0-9Xx]$";
    
    // 权重因子（用于校验码计算）
    private static final int[] WEIGHT_FACTOR = {7, 9, 10, 5, 8, 4, 2, 1, 6, 3, 7, 9, 10, 5, 8, 4, 2};
    
    // 校验码对应表
    private static final char[] CHECK_CODE = {'1', '0', 'X', '9', '8', '7', '6', '5', '4', '3', '2'};

    /**
     * 验证身份证号码格式是否正确
     * @param idCard 身份证号码
     * @return 是否有效
     * @throws IllegalArgumentException 如果身份证格式错误
     */
    public static boolean validate(String idCard) {
        if (idCard == null || idCard.trim().isEmpty()) {
            throw new IllegalArgumentException("身份证号码不能为空");
        }
        
        idCard = idCard.trim();
        
        // 检查长度
        if (idCard.length() != 15 && idCard.length() != 18) {
            throw new IllegalArgumentException("身份证号码长度必须是15位或18位");
        }
        
        // 检查格式
        if (idCard.length() == 18) {
            return validate18DigitIdCard(idCard);
        } else {
            return validate15DigitIdCard(idCard);
        }
    }

    /**
     * 验证18位身份证号码
     */
    private static boolean validate18DigitIdCard(String idCard) {
        // 基础格式验证
        if (!Pattern.matches(ID_CARD_18_REGEX, idCard)) {
            throw new IllegalArgumentException("身份证号码格式不正确");
        }
        
        // 验证出生日期
        if (!validateBirthDate(idCard.substring(6, 14))) {
            throw new IllegalArgumentException("身份证号码中的出生日期无效");
        }
        
        // 验证校验码
        if (!validateCheckCode(idCard)) {
            throw new IllegalArgumentException("身份证号码校验码错误");
        }
        
        return true;
    }

    /**
     * 验证15位身份证号码
     */
    private static boolean validate15DigitIdCard(String idCard) {
        // 基础格式验证
        if (!Pattern.matches(ID_CARD_15_REGEX, idCard)) {
            throw new IllegalArgumentException("身份证号码格式不正确");
        }
        
        // 验证出生日期（15位身份证年份为2位，需要转换为4位）
        String birthDateStr = "19" + idCard.substring(6, 12);
        if (!validateBirthDate(birthDateStr)) {
            throw new IllegalArgumentException("身份证号码中的出生日期无效");
        }
        
        return true;
    }

    /**
     * 验证出生日期是否有效
     */
    private static boolean validateBirthDate(String birthDateStr) {
        try {
            LocalDate birthDate = LocalDate.parse(birthDateStr, DateTimeFormatter.ofPattern("yyyyMMdd"));
            
            // 检查日期是否在合理范围内（1900年至今）
            LocalDate minDate = LocalDate.of(1900, 1, 1);
            LocalDate maxDate = LocalDate.now();
            
            if (birthDate.isBefore(minDate) || birthDate.isAfter(maxDate)) {
                return false;
            }
            
            return true;
        } catch (DateTimeParseException e) {
            return false;
        }
    }

    /**
     * 验证18位身份证校验码
     */
    private static boolean validateCheckCode(String idCard) {
        int sum = 0;
        
        // 计算前17位的加权和
        for (int i = 0; i < 17; i++) {
            int digit = Character.getNumericValue(idCard.charAt(i));
            sum += digit * WEIGHT_FACTOR[i];
        }
        
        // 计算校验码
        int mod = sum % 11;
        char expectedCheckCode = CHECK_CODE[mod];
        char actualCheckCode = Character.toUpperCase(idCard.charAt(17));
        
        return expectedCheckCode == actualCheckCode;
    }

    /**
     * 提取出生日期
     */
    public static LocalDate extractBirthDate(String idCard) {
        validate(idCard); // 先验证格式
        
        if (idCard.length() == 18) {
            String birthDateStr = idCard.substring(6, 14);
            return LocalDate.parse(birthDateStr, DateTimeFormatter.ofPattern("yyyyMMdd"));
        } else {
            String birthDateStr = "19" + idCard.substring(6, 12);
            return LocalDate.parse(birthDateStr, DateTimeFormatter.ofPattern("yyyyMMdd"));
        }
    }

    /**
     * 提取性别（1-男，2-女）
     */
    public static int extractGender(String idCard) {
        validate(idCard); // 先验证格式
        
        int genderDigit;
        if (idCard.length() == 18) {
            genderDigit = Character.getNumericValue(idCard.charAt(16));
        } else {
            genderDigit = Character.getNumericValue(idCard.charAt(14));
        }
        
        return genderDigit % 2 == 1 ? 1 : 2; // 奇数-男，偶数-女
    }
}